Check the hypercall number in the privcmd hypercall ioctl.
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 9 Feb 2006 23:16:53 +0000 (00:16 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 9 Feb 2006 23:16:53 +0000 (00:16 +0100)
We check it is a member of a small set of permitted hypercalls.
Fix libxenstat to not use multicalls (not permitted, and not
need for efficiency in libxenstat).

Based on an original patch by Chris Wright.

Signed-off-by: Keir Fraser <keir@xensource.com>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c
tools/xenstat/libxenstat/src/xen-interface.c

index 7758ca5cd936db44f6d975a3db3ac6a96b595c16..52364f9aeb6bb4079f7b72ff20a3a5d04eec4009 100644 (file)
@@ -35,6 +35,9 @@
 static struct proc_dir_entry *privcmd_intf;
 static struct proc_dir_entry *capabilities_intf;
 
+#define NR_HYPERCALLS 32
+static DECLARE_BITMAP(hypercall_permission_map, NR_HYPERCALLS);
+
 static int privcmd_ioctl(struct inode *inode, struct file *file,
                          unsigned int cmd, unsigned long data)
 {
@@ -48,6 +51,12 @@ static int privcmd_ioctl(struct inode *inode, struct file *file,
                if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
                        return -EFAULT;
 
+               /* Check hypercall number for validity. */
+               if (hypercall.op >= NR_HYPERCALLS)
+                       return -EINVAL;
+               if (!test_bit(hypercall.op, hypercall_permission_map))
+                       return -EINVAL;
+
 #if defined(__i386__)
                __asm__ __volatile__ (
                        "pushl %%ebx; pushl %%ecx; pushl %%edx; "
@@ -260,6 +269,15 @@ static int capabilities_read(char *page, char **start, off_t off,
 
 static int __init privcmd_init(void)
 {
+       /* Set of hypercalls that privileged applications may execute. */
+       set_bit(__HYPERVISOR_acm_op,           hypercall_permission_map);
+       set_bit(__HYPERVISOR_dom0_op,          hypercall_permission_map);
+       set_bit(__HYPERVISOR_event_channel_op, hypercall_permission_map);
+       set_bit(__HYPERVISOR_memory_op,        hypercall_permission_map);
+       set_bit(__HYPERVISOR_mmu_update,       hypercall_permission_map);
+       set_bit(__HYPERVISOR_mmuext_op,        hypercall_permission_map);
+       set_bit(__HYPERVISOR_xen_version,      hypercall_permission_map);
+
        privcmd_intf = create_xen_proc_entry("privcmd", 0400);
        if (privcmd_intf != NULL)
                privcmd_intf->proc_fops = &privcmd_file_ops;
index 8c06449db3e19aef26e51dd2ef1297effb73394c..6b6fa6b9fbfbded631e2793673dc2257f2098d5a 100644 (file)
@@ -61,43 +61,40 @@ static int xi_make_xen_version_hypercall(xi_handle *handle, long *vnum,
                                         xen_extraversion_t *ver)
 {
        privcmd_hypercall_t privcmd;
-       multicall_entry_t multicall[2];
        int ret = 0;
 
-       /* set up for doing hypercall */
-       privcmd.op = __HYPERVISOR_multicall;
-       privcmd.arg[0] = (unsigned long)multicall;
-       privcmd.arg[1] = 2;
-
-       /* first one to get xen version number */
-       multicall[0].op = __HYPERVISOR_xen_version;
-       multicall[0].args[0] = (unsigned long)XENVER_version;
-
-       /* second to get xen version flag */
-       multicall[1].op = __HYPERVISOR_xen_version;
-       multicall[1].args[0] = (unsigned long)XENVER_extraversion;
-       multicall[1].args[1] = (unsigned long)ver;
-
-       if (mlock( &privcmd, sizeof(privcmd_hypercall_t)) < 0) {
+       if (mlock(&privcmd, sizeof(privcmd)) < 0) {
                perror("Failed to mlock privcmd structure");
                return -1;
        }
 
-       if (mlock( multicall, sizeof(multicall_entry_t)) < 0) {
-               perror("Failed to mlock multicall_entry structure");
-               munlock( &multicall, sizeof(multicall_entry_t));
+       if (mlock(ver, sizeof(*ver)) < 0) {
+               perror("Failed to mlock extraversion structure");
+               munlock(&privcmd, sizeof(privcmd));
                return -1;
        }
 
-       if (ioctl( handle->fd, IOCTL_PRIVCMD_HYPERCALL, &privcmd) < 0) {
+       privcmd.op = __HYPERVISOR_xen_version;
+       privcmd.arg[0] = (unsigned long)XENVER_version;
+       privcmd.arg[1] = 0;
+
+       *vnum = ioctl(handle->fd, IOCTL_PRIVCMD_HYPERCALL, &privcmd);
+       if (*vnum < 0) {
                perror("Hypercall failed");
                ret = -1;
        }
 
-       *vnum = multicall[0].result;
+       privcmd.op = __HYPERVISOR_xen_version;
+       privcmd.arg[0] = (unsigned long)XENVER_extraversion;
+       privcmd.arg[1] = (unsigned long)ver;
 
-       munlock( &privcmd, sizeof(privcmd_hypercall_t));
-       munlock( &multicall, sizeof(multicall_entry_t));
+       if (ioctl(handle->fd, IOCTL_PRIVCMD_HYPERCALL, &privcmd) < 0) {
+               perror("Hypercall failed");
+               ret = -1;
+       }
+
+       munlock(&privcmd, sizeof(privcmd));
+       munlock(ver, sizeof(*ver));
 
        return ret;
 }